#pragma once
#include <iostream>
#include <pthread.h>
#include <vector>
#include <semaphore.h>
using namespace std;

const static int kRingQueueDefaultCap = 10;

void P(sem_t *sem)
{
    sem_wait(sem);
}
void V(sem_t *sem)
{
    sem_post(sem);
}
void Lock(pthread_mutex_t *mutex)
{
    pthread_mutex_lock(mutex);
}
void Unlock(pthread_mutex_t *mutex)
{
    pthread_mutex_unlock(mutex);
}

template <class T>
class RingQueue
{
public:
    RingQueue(int cap = kRingQueueDefaultCap)
        : cap_(cap), prod_idx_(0), cons_idx_(0)
    {
        ringqueue_.resize(cap_);
        sem_init(&p_sem, 0, cap_); // 初始值为容量
        sem_init(&c_sem, 0, 0);    // 初始值为0

        pthread_mutex_init(&p_mutex_, nullptr);
        pthread_mutex_init(&c_mutex_, nullptr);
    }

    ~RingQueue()
    {
        sem_destroy(&p_sem);
        sem_destroy(&c_sem);
    }

    void Push(const T &in)
    {
        P(&p_sem); // 关注空间资源
        Lock(&p_mutex_);
        ringqueue_[prod_idx_] = in;
        prod_idx_ = (prod_idx_ + 1) % cap_;
        Unlock(&p_mutex_);
        V(&c_sem); // 通知消费者可以消费数据了
    }

    void Pop(T *out)
    {
        P(&c_sem); // 关注数据资源
        Lock(&c_mutex_);
        *out = ringqueue_[cons_idx_];
        cons_idx_++;
        cons_idx_ %= cap_;
        Unlock(&c_mutex_);
        V(&p_sem); // 通知生产者可以生产数据了
    }

private:
    vector<T> ringqueue_;
    int cap_;      // 容量
    int prod_idx_; // 生产者下标
    int cons_idx_; // 消费者下标
    sem_t p_sem;   // 生产者关注空间资源
    sem_t c_sem;   // 消费者关注数据资源

    pthread_mutex_t p_mutex_; // 保护生产者下标
    pthread_mutex_t c_mutex_; // 保护消费者下标
};